package spring.springbucks.inteceptor;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.util.HashMap;
import java.util.Map;

@Aspect
@Component
@Slf4j
public class ApiInterceptor {

  private static final String REQUEST_GET_LOG = "Request --> U:[{}] URL:[{}-{}] - Class:[{}] - Data:[{}] - Header:[{}]";

  private static final String REQUEST_RETURN_LOG = "RequestReturn --> Class:[{}] - ExecuteTime:{}";

  private static final String EX_REQUEST_RETURN_LOG = "RequestReturn --> Class:[{}] - ExecuteTime:{} - Exception:{}";

  private static final String USER_AGENT = "User-Agent";

  ThreadLocal<Long> startTime = new ThreadLocal<>();

  @Pointcut("execution(* spring.springbucks.controller.*.*(..)) ")
  public void controllerInterceptor() {
  }

  /**
   * @param joinPoint
   */
  @Before("controllerInterceptor()")
  public void doBefore(JoinPoint joinPoint) {
    startTime.set(System.currentTimeMillis());
    StringBuilder executeMethod = new StringBuilder();
    executeMethod.append(joinPoint.getSignature().getDeclaringTypeName()).append(" # ");
    executeMethod.append(joinPoint.getSignature().getName());
    StringBuilder params = new StringBuilder();
    if (joinPoint.getArgs() != null) {
      params.append(JSONUtil.parseArray(joinPoint.getArgs()));
    }
    ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    HttpServletRequest request = attributes.getRequest();

    // 截取Parameter中参数
    if (CollectionUtil.isNotEmpty(request.getParameterMap())) {
      params.append(JSONUtil.toJsonStr(request.getParameterMap()));
    }

    // 增加头参数
    Map<String, String> headers = new HashMap<>();
    headers.put(USER_AGENT, request.getHeader(USER_AGENT));
    String headerString = JSONUtil.toJsonStr(headers);
    log.info(REQUEST_GET_LOG, request.getMethod(), request.getRequestURL().toString(), executeMethod, params, headerString);

  }

  /**
   * @param ret
   */
  @AfterReturning(returning = "ret", pointcut = "controllerInterceptor()")
  public void doAfterReturning(JoinPoint joinPoint, Object ret) {
    StringBuilder executeMethod = new StringBuilder();
    executeMethod.append(joinPoint.getSignature().getDeclaringTypeName()).append(" # ");
    executeMethod.append(joinPoint.getSignature().getName());
    log.info(REQUEST_RETURN_LOG, executeMethod, (System.currentTimeMillis() - startTime.get()));
  }

  /**
   * Exception Handler
   *
   * @param joinPoint
   * @param ex
   */
  @AfterThrowing(pointcut = "controllerInterceptor()", throwing = "ex")
  public void doAfterThrowing(JoinPoint joinPoint, Throwable ex) {
    StringBuilder exceptionMethod = new StringBuilder();
    exceptionMethod.append(joinPoint.getTarget().getClass().getName());
    exceptionMethod.append(" # ");
    exceptionMethod.append(joinPoint.getSignature().getName());

    StringBuilder classMethod = new StringBuilder();
    classMethod.append(joinPoint.getTarget().getClass().getCanonicalName());

    // 业务异常只输出信息
    log.error(EX_REQUEST_RETURN_LOG, exceptionMethod.toString(), (System.currentTimeMillis() - startTime.get()), ex);
  }

}
